package com.simpou.commons.utils.file;

import com.simpou.commons.utils.TestsConstants;
import com.simpou.commons.utils.file.BundleHelper;
import com.simpou.commons.utils.file.FileHelper;
import com.simpou.commons.utils.file.PropertyHelper;
import com.simpou.commons.utils.string.StringLocales;
import com.simpou.commons.utils.string.Strings;
import com.simpou.commons.utils.tests.TestRunner;
import com.simpou.commons.utils.tests.annot.ClassTest;
import com.simpou.commons.utils.tests.annot.ExtraTest;

import org.junit.After;
import org.junit.AfterClass;
import static org.junit.Assert.*;

import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import org.junit.runner.RunWith;

import java.io.FileNotFoundException;
import java.io.IOException;

import java.util.Locale;
import java.util.MissingResourceException;
import java.util.Set;


@RunWith(TestRunner.class)
@ClassTest(BundleHelper.class)
public class BundleHelperITCase {
    private static BundleHelper bundleHelper;
    private static BundleHelper bundleHelperEN;
    private static String bundle;
    private static String key;
    private static String key2;
    private static String param;
    private static String contentDef;
    private static String contentEN;
    private static String bundlePath;
    private static String bundlePathEN;
    private static String bundleWithDirPath;
    private static final String bundleName = "bundleTest";
    private static final String bundleNameWithDir = "reldir/" + bundleName;
    private static final String localeStringEN = "_en_US";
    private static final String contentEnumDef = "elemento";
    private static final String contentEnumEN = "element";

    @BeforeClass
    public static void setUpClass() throws Exception {
        // cria arquivos de bundle direto no diretório de classes para 
        // funcionar em runtime
        String baseDirClass = TestsConstants.TEST_CLASSES_DIR;
        bundlePath = baseDirClass + bundleName +
            PropertyHelper.FILE_PROPS_EXTENSION;
        bundlePathEN = baseDirClass + bundleName + localeStringEN +
            PropertyHelper.FILE_PROPS_EXTENSION;
        bundleWithDirPath = baseDirClass + bundleNameWithDir +
            PropertyHelper.FILE_PROPS_EXTENSION;

        String content = " {0}.";
        key = "message";
        key2 = "message2";
        contentDef = "Olá" + content;
        contentEN = "Hello" + content;

        // gera arquivos no resources
        String enumKeyName = TestsConstants.ENUM_BUNDLE_KEY_PREFIX +
            TestEnum.ELEMENT.name();

        FileHelper.write(bundlePath, key + "=" + contentDef, false, false);
        FileHelper.write(bundlePath, "\n" + enumKeyName + "=" + contentEnumDef,
            true, false);
        assertTrue(FileHelper.exists(bundlePath));

        FileHelper.write(bundlePathEN, key + "=" + contentEN, false, false);
        FileHelper.write(bundlePathEN,
            "\n" + enumKeyName + "=" + contentEnumEN, true, false);
        assertTrue(FileHelper.exists(bundlePathEN));

        FileHelper.write(bundleWithDirPath, " ", false, false);
        assertTrue(FileHelper.exists(bundleWithDirPath));

        // configura chave
        param = PropertyHelper.getUser();
    }

    @AfterClass
    public static void tearDownClass() throws Exception {
        FileHelper.delete(bundlePath);
        FileHelper.delete(bundlePathEN);
        FileHelper.delete(bundleWithDirPath);

        if (!PropertyHelper.isWindows()) {
            assertFalse(FileHelper.exists(bundlePath));
            assertFalse(FileHelper.exists(bundlePathEN));
            assertFalse(FileHelper.exists(bundleWithDirPath));
        }
    }

    @Before
    public void setUp() throws IOException {
        Locale.setDefault(new Locale("pt", "BR"));
        bundleHelper = new BundleHelper(bundleName);
        bundleHelperEN = new BundleHelper(bundleName, Locale.US);
    }

    @After
    public void tearDown() throws IOException {
        bundleHelper.close();
        bundleHelperEN.close();
    }

    @ExtraTest
    @Test(expected = MissingResourceException.class)
    public void testNewInstance_invalid() throws IOException {
        new BundleHelper(bundleName + "error");
    }

    @Test
    @ExtraTest
    public void testNewInstance_withDir() throws IOException {
        // testa bundle em subdiretórios
        new BundleHelper(bundleNameWithDir);
    }

    @Test
    public void testGetBundle_String() throws Exception {
        // obtém bundle em portugues
        bundle = bundleHelper.getBundle(key);
        assertEquals(Strings.replaceParams(contentDef), bundle);

        // obtém bundle em inglês
        bundle = bundleHelperEN.getBundle(key);
        assertEquals(Strings.replaceParams(contentEN), bundle);
    }

    @Test
    public void testGetBundle_String_ObjectArr() throws Exception {
        // obtém bundle em portugues
        bundle = bundleHelper.getBundle(key, param);
        assertEquals(Strings.replaceParams(contentDef, param), bundle);

        // obtém bundle em inglês
        bundle = bundleHelperEN.getBundle(key, param);
        assertEquals(Strings.replaceParams(contentEN, param), bundle);

        bundle = bundleHelperEN.getBundle(key, new String[0]);
        assertEquals(contentEN, bundle);
    }

    @Test
    public void testGetBundle_created() throws IOException {
        // cria bundle
        bundle = bundleHelper.getBundle(key2);

        // verifica se o bundle foi criado em todos arquivos
        String text = FileHelper.read(bundlePath);
        assertTrue(text.contains(key2 + "="));

        String textEN = FileHelper.read(bundlePathEN);
        assertTrue(textEN.contains(key2 + "="));
    }

    @Test
    public void testClose() {
        //tearDown
    }

    @Test
    public void testGetLocalesAvaiable() throws FileNotFoundException {
        Set<Locale> localesAvaiable = bundleHelper.getLocalesAvaiable(bundleName);
        assertEquals(1, localesAvaiable.size());
        assertTrue(localesAvaiable.contains(StringLocales.getStringAsLocale(
                    localeStringEN.substring(1))));
    }
    private enum TestEnum {ELEMENT;
    }
}
